package multithreading;

import java.util.Random;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;

/**
 * CompletableFuture使用案例
 * 小明区餐厅点餐-->厨师做菜和服务员蒸饭和小明在看书-->服务员打饭-->小明开始吃饭
 * 小明吃饭完后-->小明先买单-->服务员开发票-->小明离开
 * 小明打算做公交车回家-->在公交车站等123/456路公交车（123出问题就打车回去）-->小明回家
 * supplyAsync
 * thenCombine
 * thenApply
 * applyToEither
 * applyToEither
 * exceptionally
 */
public class CompletableFutureDemo1 {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        System.out.println(Thread.currentThread().getName() + ": 小明到餐厅准备点了西红柿炒鸡蛋和米饭");
        // ***********************小明区餐厅点餐-->厨师做菜和服务员蒸饭和小明在看书-->服务员打饭-->小明开始吃饭
        CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
            int time = new Random().nextInt(5000) + 1000;
            System.out.println(Thread.currentThread().getName() + ": 厨师正在做西红柿炒鸡蛋" + "=====" + time);
            try {
                Thread.sleep(time);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return "西红柿炒鸡蛋做好了";
        }).thenCombine(CompletableFuture.supplyAsync(() -> {
            int time = new Random().nextInt(5000) + 1000;
            System.out.println(Thread.currentThread().getName() + ": 服务员正在蒸米饭" + "=====" + time);
            try {
                Thread.sleep(time);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return "米饭蒸好了";
        }), (s, s2) -> {
            int time = new Random().nextInt(5000) + 1000;
            System.out.println(Thread.currentThread().getName() + ": 服务员开始打饭" + "=====" + time);
            try {
                Thread.sleep(time);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return s + "," + s2;
        });
        int t = new Random().nextInt(5000) + 1000;
        Thread.sleep(t);
        System.out.println(Thread.currentThread().getName() + ": 小明在等餐的时候，开始看书" + "=====" + t);
        future.join();
        System.out.println(Thread.currentThread().getName() + ": 小明开始吃饭");

        //  ***********************小明吃饭完后-->小明先买单-->服务员开发票-->小明离开
        System.out.println(Thread.currentThread().getName() + ": 小明吃完饭");
        future = CompletableFuture.supplyAsync(() -> {
            int money = new Random().nextInt(1000);
            System.out.println(Thread.currentThread().getName() + ": 小明先买单,付了" + money + "钱");
            int time = new Random().nextInt(5000) + 1000;
            try {
                Thread.sleep(time);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return money;
        }).thenApply(s -> {
            System.out.println(Thread.currentThread().getName() + ": 服务员给小明开了" + s + "元的发票");
            int time = new Random().nextInt(5000) + 1000;
            try {
                Thread.sleep(time);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return s + "元";
        });
        future.join();
        // ***********************小明打算做公交车回家-->在公交车站等123/456路公交车（123出问题就打车回去）-->小明回家
        System.out.println("小明离开餐厅,来到公交车站等123/456路公交车到来");
        future = CompletableFuture.supplyAsync(() -> {
            int time = new Random().nextInt(5000) + 1000;
            System.out.println(Thread.currentThread().getName() + ": 小明在公交车站等123路公交车到来" + "=====" + time);
            try {
                Thread.sleep(time);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return "123到站了";

        }).applyToEither(CompletableFuture.supplyAsync(() -> {
            int time = new Random().nextInt(5000) + 1000;
            System.out.println(Thread.currentThread().getName() + ": 小明在公交车站等456路公交车到来" + "=====" + time);
            try {
                Thread.sleep(time);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return "456到站了";
        }), (s) -> {
            if (s.startsWith("123")) {
                System.out.println(Thread.currentThread().getName() + ": 123出故障了");
                throw new RuntimeException("123出故障了");
            }
            return s;
        }).exceptionally(throwable -> {
            int time = new Random().nextInt(5000) + 1000;
            System.out.println(Thread.currentThread().getName() + ": 小明呼叫出租车" + "=====" + time);
            try {
                Thread.sleep(time);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
            return "出租车到了";
        });
        future.join();
        if (future.get().startsWith("出租车")) {
            System.out.println("小明坐上出租车回家");
        } else {
            System.out.println("小明坐上456路公交车回家");
        }
    }
}
